package com.whfc.mach.manager.strategy.oil;

import com.whfc.common.util.JSONUtil;
import com.whfc.common.util.MathUtil;
import com.whfc.mach.dto.AppMachOilLookup;
import com.whfc.mach.dto.Oil;
import com.whfc.mach.dto.OilStat;
import com.whfc.mach.manager.util.MachOilUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * @Description: 油量计算算法 (融合中值过滤)
 * @author: xugcheng
 * @version: 1.0
 * @date: 2020-12-11 9:54
 */
public class DiffOilStrategy implements OilStrategy {

    private Logger logger = LoggerFactory.getLogger(DiffOilStrategy.class);

    /**
     * 最少数据点量
     */
    private static final int DATA_POINT_MIN_NUMS = 2;

    /**
     * 最小加油阈值(25%)
     */
    private static final double MIN_OIL_ADD_THRESHOLD = 0.25;

    @Override
    public OilStat compute(List<Oil> oilList, Double oilTankHeight, Double oilTankVolume) {
        OilStat stat = new OilStat();
        if (oilTankHeight != null && oilTankHeight > 0 && oilTankVolume != null && oilTankVolume > 0) {
            if (oilList != null && oilList.size() >= DATA_POINT_MIN_NUMS) {

                //油位值修正
                oilList = MachOilUtil.amendMachOil(oilList, oilTankHeight);

                //判定加油(大幅度的油位上升)
                double minOilAddDiff = oilTankHeight * 10 * MIN_OIL_ADD_THRESHOLD;
                double oilAddPosDiff = 0;
                for (int i = 0; i < oilList.size() - 1; i++) {
                    Oil curOil = oilList.get(i);
                    Oil nextOil = oilList.get(i + 1);
                    double diff = nextOil.getOilPos() - curOil.getOilPos();
                    if (diff > minOilAddDiff) {
                        oilAddPosDiff += diff;
                        logger.info("判定加油,cur:{},next:{},diff:{}", JSONUtil.toString(curOil), JSONUtil.toString(nextOil), oilAddPosDiff);
                    }
                }

                //判定油耗
                if (oilList.size() > 0) {
                    double oilWearPosDiff = (oilList.get(0).getOilPos() - oilList.get(oilList.size() - 1).getOilPos()) + oilAddPosDiff;
                    oilWearPosDiff = oilWearPosDiff >= 0 ? oilWearPosDiff : 0;
                    double oilAdd = MathUtil.round((oilAddPosDiff * oilTankVolume) / (oilTankHeight * 10), 2);
                    double oilWear = MathUtil.round((oilWearPosDiff * oilTankVolume) / (oilTankHeight * 10), 2);
                    stat.setOilAdd(oilAdd);
                    stat.setOilWear(oilWear);
                }
                logger.info("oil_stat:{}", JSONUtil.toString(stat));
            }
        }
        return stat;
    }

    @Override
    public OilStat compute(List<Oil> oilList, Double oilTankHeight, Double oilTankVolume, AppMachOilLookup lookup) {

        //速查表为空,直接按照油位百分比计算
        if (lookup == null || lookup.getOilSheetMap() == null || lookup.getOilSheetMap().isEmpty()) {
            return this.compute(oilList, oilTankHeight, oilTankVolume);
        }

        OilStat stat = new OilStat();
        if (oilTankHeight != null && oilTankHeight > 0 && oilTankVolume != null && oilTankVolume > 0) {
            if (oilList != null && oilList.size() >= DATA_POINT_MIN_NUMS) {

                //油位值修正
                oilList = MachOilUtil.amendMachOil(oilList, oilTankHeight);

                //判定加油(大幅度的油位上升)
                double minOilAdd = oilTankVolume * MIN_OIL_ADD_THRESHOLD;
                double oilAdd = 0;
                for (int i = 2; i < oilList.size() - 2; i++) {
                    double preOil = MachOilUtil.getOilVolume(lookup, oilList.get(i - 1).getOilPos());
                    double curOil = MachOilUtil.getOilVolume(lookup, oilList.get(i).getOilPos());
                    double nextOil1 = MachOilUtil.getOilVolume(lookup, oilList.get(i + 1).getOilPos());
                    double nextOil2 = MachOilUtil.getOilVolume(lookup, oilList.get(i + 2).getOilPos());
                    double preDiff = curOil - preOil;
                    double curDiff = nextOil1 - curOil;
                    double nextDiff = nextOil2 - nextOil1;
                    if (preDiff > minOilAdd || curDiff > minOilAdd || nextDiff > minOilAdd) {
                        if (curDiff > 0) {
                            oilAdd += curDiff;
                            logger.info("判定加油,preDiff:{},curDiff:{},nextDiff:{}", preDiff, curDiff, nextDiff);
                        }
                    }
                }

                //判定油耗
                if (oilList.size() > 0) {
                    Oil startOil = oilList.get(0);
                    Oil endOil = oilList.get(oilList.size() - 1);
                    double startOilVol = MachOilUtil.getOilVolume(lookup, startOil.getOilPos());
                    double endOilVol = MachOilUtil.getOilVolume(lookup, endOil.getOilPos());
                    double oilWear = startOilVol - endOilVol + oilAdd;
                    oilWear = oilWear >= 0 ? oilWear : 0;
                    stat.setOilAdd(oilAdd);
                    stat.setOilWear(oilWear);
                }
                logger.info("oil_stat:{}", JSONUtil.toString(stat));
            }
        }
        return stat;
    }

    @Override
    public Oil computeRemainOil(Integer oilPos, Double oilTankHeight, Double oilTankVolume, AppMachOilLookup lookup) {
        Double remainOil = 0D;
        Double remainOilFactor = 0D;
        if (oilTankHeight != null && oilTankHeight > 0 && oilTankVolume != null && oilTankVolume > 0 && oilPos != null && oilPos >= 0) {

            //油位值修正
            oilPos = MachOilUtil.amendMachOil(oilPos, oilTankHeight);

            //有油位标定数据,查询标定关系
            boolean isLookUpExists = lookup != null && lookup.getOilSheetMap() != null && !lookup.getOilSheetMap().isEmpty();
            if (isLookUpExists) {
                remainOil = MachOilUtil.getOilVolume(lookup, oilPos);
                remainOilFactor = remainOil / oilTankVolume;
            }
            //没有油位标定数据,则按规则容器处理
            else {
                Double maxHeight = oilTankHeight * 10;
                Double curHeight = oilPos > maxHeight ? maxHeight : oilPos;
                remainOil = (curHeight / maxHeight) * oilTankVolume;
                remainOilFactor = curHeight / maxHeight;
            }
        }
        Oil oil = new Oil();
        oil.setOilPos(oilPos);
        oil.setRemainOil(MathUtil.round(remainOil, 2));
        oil.setRemainOilPercent(MathUtil.round(remainOilFactor * 100, 2));
        return oil;
    }

    @Override
    public List<Oil> computeRemainOil(List<Oil> oilList, Double oilTankHeight, Double oilTankVolume, AppMachOilLookup lookup) {
        if (oilList != null && !oilList.isEmpty()) {

            //油位值修正
            logger.info("修正前数量-{}", oilList.size());
            oilList = MachOilUtil.amendMachOil(oilList, oilTankHeight);
            logger.info("修正后数量-{}", oilList.size());

            //计算油位
            boolean isLookUpExists = lookup != null && lookup.getOilSheetMap() != null && !lookup.getOilSheetMap().isEmpty();
            for (Oil oil : oilList) {
                Double remainOil;
                Double remainOilFactor;
                //有油位标定数据,查询标定关系
                if (isLookUpExists) {
                    remainOil = MachOilUtil.getOilVolume(lookup, oil.getOilPos());
                    remainOilFactor = remainOil / oilTankVolume;
                }
                //没有油位标定数据,则按规则容器处理
                else {
                    Double maxHeight = oilTankHeight * 10;
                    Double curHeight = oil.getOilPos() > maxHeight ? maxHeight : oil.getOilPos();
                    remainOil = (curHeight / maxHeight) * oilTankVolume;
                    remainOilFactor = curHeight / maxHeight;
                }
                oil.setRemainOil(MathUtil.round(remainOil, 2));
                oil.setRemainOilPercent(MathUtil.round(remainOilFactor * 100, 2));
            }
        }
        return oilList;
    }
}
